#include "GeometryInteriorPointExtractor.h"
#include <TGS/GeoMath2.0/Delaunay.h>
#include <TGS/GeoMath2.0/Polygon.h>
#include <TGS/GeoMath2.0/Point.h>
#include <TGS/GeoMath2.0/Vector.h>
#include <vector>
#include <algorithm>

using namespace std;
using namespace TGS::GeoMath;

namespace
{

	double getTriangleAera(int triangleIndex, const Delaunay& delaunay)
	{
		const Delaunay::DelaunayTriangulation* delaunayTriangulation = delaunay.getDelaunayTriangulation();
		vector<Point> Points;
		for (size_t i = 0; i < delaunayTriangulation->trianglePointsIndices[triangleIndex].size(); ++i)
		{
			size_t index = delaunayTriangulation->trianglePointsIndices[triangleIndex][i];
			Points.push_back(delaunayTriangulation->points[index]);
		}

		double AeraTimes = 0.0;
		for (size_t i = 0; i < Points.size(); ++i)
		{	
			const Point& FrontPoint = Points[i];
			const Point& BackPoint = Points[(i + 1) % Points.size()];
			AeraTimes += Vector::Cross(Vector(FrontPoint.getX(), FrontPoint.getY()), 
				Vector(BackPoint.getX(), BackPoint.getY()));
		}

		return AeraTimes > 0.0 ? AeraTimes / 2.0 : AeraTimes / -2.0;	
	}

	Point getTriangleCentroid(int TriangleIndex, const Delaunay& delaunay)
	{
		const Delaunay::DelaunayTriangulation* DelaunayTriangulation = delaunay.getDelaunayTriangulation();
		vector<Point> points;
		for (size_t i = 0; i < DelaunayTriangulation->trianglePointsIndices[TriangleIndex].size(); ++i)
		{
			size_t index = DelaunayTriangulation->trianglePointsIndices[TriangleIndex][i];
			points.push_back(DelaunayTriangulation->points[index]);
		}

		double x = 0.0;
		double y = 0.0;

		for_each(points.begin(), points.end(), [&](const Point& point)
		{
			x += point.getX();
			y += point.getY();
		});

		x /= 3.0;
		y /= 3.0;

		return  Point(x, y);
	}

}


namespace TGS{
namespace GeoMath{


Point GeometryInteriorPointExtractor::extractPolygonInteriorPoint(const Polygon& polygn)
{

	Delaunay delaunay(polygn);
	delaunay.buildDelaunayTriangulation(Delaunay::PolygonCreateDelaunayTriangulation);	
	const Delaunay::DelaunayTriangulation* delaunayTriangulation = delaunay.getDelaunayTriangulation();

	if(delaunayTriangulation->tranglesCount == 0) return Point(0, 0);

	vector<double> trianglesAera;
	for (size_t i = 0; i < delaunayTriangulation->tranglesCount; ++i)
	{
		double aera = getTriangleAera(i, delaunay);
		trianglesAera.push_back(aera);
	}

	auto iter = max_element(trianglesAera.begin(), trianglesAera.end());
	size_t maxTriangleAeraIndex = iter - trianglesAera.begin();

	return getTriangleCentroid(maxTriangleAeraIndex, delaunay);
}


} // Nmo
} // Algorithm